<template>
    <div class="rtVoice_box">
        <div class="rtVoice_audioFrameMsg">{{ ws_audioFrameDurTxt }}，{{ ws_audioFrameCount }}帧，{{ ws_audioFrameSize }}字节</div>
        <div class="rtVoice_voiceReceiveMsg">{{ ws_voiceReceiveDurTxt }}，{{ ws_voiceReceiveCount }}帧，{{ ws_voiceReceiveSize }}字节</div>
        <div class="rtVoice_voiceSendMsg">
            发送：{{ ws_voiceSendDurTxt }}，{{ ws_voiceSendUserCount }}人接收，OK {{ ws_voiceSendOKCount }}帧，Err {{ ws_voiceSendErrCount }}帧，{{ ws_voiceSendSize }}字节
        </div>

        <div class="rtVoice_input_box">
            <input v-model="wsApi" placeholder="WebSocket API" class="rtVoice_input" />
            <input v-model="wsID1" placeholder="我的标识" class="rtVoice_input" />
            <input v-model="wsID2" placeholder="对方标识" class="rtVoice_input" />

            <v-btn class="text-button" @click="wsConnClick">连接 WebSocket</v-btn>
            <v-btn class="text-button" @click="wsDisconnClick">断开 WebSocket</v-btn>
            <v-btn class="text-button" @click="wsAudioStartClick">开始语音</v-btn>
            <v-btn class="text-button" @click="wsAudioStopClick">停止语音</v-btn>
            <v-btn class="text-button" @click="wsOpenVoiceClick">开始对讲</v-btn>
            <v-btn class="text-button" @click="wsCloseVoiceClick">结束对讲</v-btn>
        </div>
    </div>
</template>

<script>
export default {
  name: 'WebSocketAudioComponent',
  data() {
    return {
      wsApi: localStorage.Rec_RtVoice_wsApi || '',
      wsID1: localStorage.Rec_RtVoice_wsID1 || '',
      wsID2: localStorage.Rec_RtVoice_wsID2 || '',
      ws_audioFrameCount: 0,
      ws_audioFrameSize: 0,
      ws_audioFrameDur: 0,
      ws_audioFrameDurTxt: '00:00',
      ws_voiceSendUserCount: 0,
      ws_voiceSendOKCount: 0,
      ws_voiceSendErrCount: 0,
      ws_voiceSendSize: 0,
      ws_voiceSendDur: 0,
      ws_voiceSendDurTxt: '00:00',
      ws_voiceReceiveCount: 0,
      ws_voiceReceiveSize: 0,
      ws_voiceReceiveDur: 0,
      ws_voiceReceiveDurTxt: '00:00',
      socket: null,
      socketIsOpen: false,
    };
  },
  methods: {
    setData() {
      this.$forceUpdate(); // 强制更新 UI 显示
    },
    log(message, level = 0) {
      console.log(message); // 这里可以根据需求使用 console 或 UI 来展示日志
    },
    formatTime(ms, showSS) {
      const ss = ms % 1000;
      ms = (ms - ss) / 1000;
      const s = ms % 60;
      ms = (ms - s) / 60;
      const m = ms % 60;
      ms = (ms - m) / 60;
      const h = ms;
      let v = '';
      if (h > 0) v += `${(h < 10 ? '0' : '') + h}:`;
      v += `${(m < 10 ? '0' : '') + m}:`;
      v += (s < 10 ? '0' : '') + s;
      if (showSS) v += `″${(`00${ss}`).substr(-3)}`;
      return v;
    },
    checkSet(api) {
      if (api === 2) {
        if (!/^wss?:\/\/.+/i.test(this.wsApi) || /局域网/.test(this.wsApi)) {
          this.log('请配置ws地址，比如填写：ws://127.0.0.1:9529/', 1);
          return false;
        }
        localStorage.Rec_RtVoice_wsApi = this.wsApi;

        if (!this.wsID1) {
          this.log('请填写我的标识');
          return false;
        }
        localStorage.Rec_RtVoice_wsID1 = this.wsID1;
      }
      return true;
    },
    wsConnClick() {
      if (!this.checkSet(2)) return;
      this.log(`正在连接${this.wsApi}...`);
      if (this.socket) this.socket.close();
      const sid = (this.SID = (this.SID || 0) + 1); // 同步操作

      this.socketIsOpen = false;
      this.socket = new WebSocket(this.wsApi);
      this.socket.binaryType = 'arraybuffer';
      this.socket.onclose = () => {
        if (sid !== this.SID) return;
        this.socketIsOpen = false;
        this.log('ws已断开');
      };
      this.socket.onerror = (e) => {
        if (sid !== this.SID) return;
        this.socketIsOpen = false;
        this.log(`ws因为错误已断开：${e.message}`, 1);
      };
      this.socket.onopen = () => {
        if (sid !== this.SID) return;
        this.socketIsOpen = true;
        this.log('ws已连接', 2);
        this.ws__sendMessage('setMeta', { uid: this.wsID1 });
      };
      this.socket.onmessage = (e) => {
        if (sid !== this.SID) return;
        this.ws__receiveMessage(e.data);
      };
    },
    wsDisconnClick() {
      if (this.socketIsOpen) this.log('ws正在断开...');
      else this.log('ws未连接');
      if (this.socket) this.socket.close();
    },
    ws__receiveMessage(rawMsg) {
      let binary = new Uint8Array(0);
      let rawTxt = rawMsg;

      if (rawMsg instanceof ArrayBuffer) {
        const bytes = new Uint8Array(rawMsg);
        let str = '';
        let bIdx = bytes.length;
        for (let i = 0; i < bytes.length; i++) {
          if (bytes[i] == 10) {
            bIdx = i + 1;
            break;
          } else str += String.fromCharCode(bytes[i]);
        }
        rawTxt = decodeURIComponent(escape(str));
        binary = new Uint8Array(bytes.buffer.slice(bIdx));
      }

      let msgObj;
      try {
        msgObj = JSON.parse(rawTxt);
      } catch (e) {
        this.log(`非JSON格式数据：${rawTxt}`, 1);
        return;
      }

      const { type } = msgObj;
      const data = msgObj.v || {};
      if (this[`onMsg__${type}`]) {
        this[`onMsg__${type}`](data, binary);
        return;
      }
      this.log(`未知消息类型：${rawTxt}`, 1);
    },
    ws__sendMessage(type, data, bytes) {
      if (!this.socketIsOpen) {
        this.log('ws连接未打开', 1);
        return;
      }
      const msgObj = { type, v: data || {} };
      const rawTxt = JSON.stringify(msgObj);
      if (bytes && bytes.length) {
        const str = unescape(encodeURIComponent(rawTxt));
        const u8arr = new Uint8Array(str.length);
        for (let i = 0; i < str.length; i++) u8arr[i] = str.charCodeAt(i);
        const arr = new Uint8Array(u8arr.length + 1 + bytes.length);
        arr.set(u8arr);
        arr[u8arr.length] = 10;
        arr.set(bytes, u8arr.length + 1);
        this.socket.send(arr.buffer);
      } else {
        this.socket.send(rawTxt);
      }
    },
    wsAudioStartClick() {
      if (!this.socketIsOpen) return this.log('ws未连接', 1);
      this.ws_audioFrameCount = 0;
      this.ws_audioFrameSize = 0;
      this.ws_audioFrameDur = 0;
      this.ws_audioFrameDurTxt = '00:00';
      this.setData();
      this.ws__sendMessage('audioStart', { readAudio: false });
    },
    wsAudioStopClick() {
      this.ws__sendMessage('audioStop', {});
    },
    onMsg__audioFrame(data, binary) {
      const pcm = new Int16Array(binary.buffer);
      this.ws_audioFrameCount++;
      this.ws_audioFrameSize += binary.length;
      this.ws_audioFrameDur = Math.round((this.ws_audioFrameSize / 2 / data.sampleRate) * 1000);
      this.ws_audioFrameDurTxt = this.formatTime(this.ws_audioFrameDur);
      this.setData();
    },
    wsOpenVoiceClick() {
      if (!this.socketIsOpen) return this.log('ws未连接', 1);
      this.log('我方已开始语音发送，请在上面实时录音函数中实时调用ws__sendMessage发送音频帧数据');
    },
    wsCloseVoiceClick() {
      this.log('结束对讲');
    },
  },
};
</script>

<style scoped>
.rtVoice_audioFrameMsg,
.rtVoice_voiceReceiveMsg,
.rtVoice_voiceSendMsg {
    margin-bottom: 10px;
}
/*.rtVoice_input_ws {*/
/*    display: block;*/
/*    margin-bottom: 10px;*/
/*}*/

.rtVoice_box{
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-top: 20px;
}

.rtVoice_input_box {
    display: flex;
    flex-direction: column;
    width: 500px;
}

.rtVoice_input {
    margin-bottom: 10px;
}

.text-button {
    margin-bottom: 10px;
}



</style>
